﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace SpaceEngine.Assets
{
    public class PlayerShip : Asset3D
    {
        Game1 game;
        Vector3 destPosition;
        Queue<Vector3> flightPathPoints;
        Line flightLine;
        int lineQuant;
        VertexPositionColor[] linePoints;
        Color lineColor;

        float destRotation;
        float rotationIncrement;
        float velocity;
        float velocityMax;
        float acceleration;
        Marker marker;

        public PlayerShip(Game1 game)
            :base(game,@"Models\spaceship_003",1f)
        {
            this.game = game;
            position = new Vector3(10,10,10);
            destPosition = position;
            rotationIncrement = MathHelper.ToRadians(1.5f);
            velocity = 0f;
            acceleration = .001f;
            velocityMax = .5f;
            lineColor = new Color(100,5,5);
            lineQuant = 2;
            linePoints = new VertexPositionColor[lineQuant];
            flightPathPoints = new Queue<Vector3>(lineQuant);
            flightPathPoints.Enqueue(position);
        }

        public override void Initialize()
        {
            base.Initialize();
            marker = new Marker(game, Vector3.Zero, "blue");
            game.Components.Add(marker);
        }

        public override void Update(GameTime gameTime)
        {
            // lock the camera to the ship
            game.camera.TargetPosition = position;
            marker.Position = new Vector3(position.X, 0, position.Z);

            // normalize rotation
            rotation.Y = (rotation.Y >= MathHelper.ToRadians(360)) ? rotation.Y - MathHelper.ToRadians(360) : rotation.Y;
            rotation.Y = (rotation.Y < 0) ? rotation.Y + MathHelper.ToRadians(360) : rotation.Y;

            // set destination, create line if clicked
            if (game.input.mouseLeftClicked)
            {
                // set destination
                destPosition = game.input.MousePosition;

                // remove line from Components collection
                if(flightLine != null && linePoints != null)
                {
                    game.Components.Remove(flightLine);
                }

                // add new destination to queue
                if (flightPathPoints.Count == lineQuant)
                {
                    flightPathPoints.Dequeue();
                }
                flightPathPoints.Enqueue(destPosition);


                // set up line points
                for (int i = 0; i < flightPathPoints.Count; i++)
                {
                    linePoints[i] = new VertexPositionColor(flightPathPoints.ElementAt(i), ((i == 0) ? Color.Black : lineColor));
                }

                // draw line
                flightLine = new Line(game, linePoints);
                game.Components.Add(flightLine);
            }

            // determine distance to target
            float dist = (float)(Math.Sqrt(Math.Pow(Math.Abs(destPosition.X - position.X), 2) + Math.Pow(Math.Abs(destPosition.Z - position.Z), 2)));
            Console.WriteLine(dist);

            if (dist > 1)
            {
                // set and normalize rotation
                Vector2 toDest = new Vector2(position.X - destPosition.X, position.Z - destPosition.Z);
                destRotation = -(float)Math.Atan2(toDest.Y, toDest.X);
                destRotation = (destRotation >= MathHelper.ToRadians(360)) ? destRotation - MathHelper.ToRadians(360) : destRotation;
                destRotation = (destRotation < 0) ? destRotation + MathHelper.ToRadians(360) : destRotation;

                if (rotation.Y != destRotation)
                {
                    // calculate rotation direction
                    float delta;
                    if (destRotation > rotation.Y)
                    {
                        delta = destRotation - rotation.Y;
                        if (delta <= rotationIncrement)
                        {
                            rotation.Y = destRotation;
                        }
                        else
                        {
                            if (delta > Math.PI)
                                rotation.Y -= rotationIncrement;
                            else
                                rotation.Y += rotationIncrement;
                        }
                    }
                    else
                    {
                        delta = rotation.Y - destRotation;
                        if (delta <= rotationIncrement)
                        {
                            rotation.Y = destRotation;
                        }
                        else
                        {
                            if (delta < Math.PI)
                                rotation.Y -= rotationIncrement;
                            else
                                rotation.Y += rotationIncrement;
                        }
                    }
                }
                else
                {
                    // we're rotated correctly, now accel if far away
                    if (dist > 20)
                        velocity = (velocity < velocityMax) ? velocity + acceleration : velocityMax;
                    else
                        velocity = (velocity > (dist / 20) * velocityMax) ? (dist / 20) * velocityMax : velocity;
                }
            }
            else
            {
                // we're as close as we can get: Stop!
                velocity = 0;
            }


            // calculations made, affect position
            position.X -= (float)Math.Cos(rotation.Y) * velocity;
            position.Z += (float)Math.Sin(rotation.Y) * velocity;

            base.Update(gameTime);
        }
    }
}
